#include "call.h"
#include "proc.h"
#include "fs.h"
#include "tools.h"

struct dentry *adpm_mount(struct file_system_type *fs_type, int flags,
          const char *dev_name, void *data)
{
  struct dentry *ret;
  adpm_pr("%s\n", __func__);
  if(atomic_add_return(1, &adpm_nr_mp) != 1){
    atomic_dec(&adpm_nr_mp);
    pr_err("at most ONE MOUNT POINT\n");
    return ERR_PTR(-EEXIST);
  }
  ret = mount_nodev(fs_type, flags, data, adpm_fill_super);
  if(IS_ERR(ret))
    return ret;
  adpm_call_register();
  adpm_create_proc();
  return ret;
}

void adpm_kill_sb(struct super_block *sb)
{
  adpm_pr("%s\n", __func__);
  adpm_remove_proc();
  adpm_clear_ftab();
  adpm_call_unregister();
  if(sb->s_fs_info){
    struct adpm_sb_info *sbi = (struct adpm_sb_info *)sb->s_fs_info;
    if(sbi->virt_addr)iounmap((void __iomem*)sbi->virt_addr);
    kfree(sb->s_fs_info);
    sb->s_fs_info = NULL;
  }
  adpm_destroy_buddy();
  atomic_dec(&adpm_nr_mp);
  kill_litter_super(sb);
}


static struct file_system_type adpm_fs = {
  .owner = THIS_MODULE,
  .name = "adpm",
  .mount = adpm_mount,
  .kill_sb = adpm_kill_sb,
};

static int adpm_init(void)
{
  int ret;
  BUILD_BUG_ON(sizeof(unsigned long) != 8);
  atomic_set(&adpm_nr_mp, 0);
  // init ib TODO

  //register the file sys
  ret = register_filesystem(&adpm_fs);
  if(ret){
    pr_err("ERROR: fail to register filesystem");
    goto out1;
  }
out1:
  return ret;
}
static void adpm_exit(void)
{
  unregister_filesystem(&adpm_fs);
}

module_init(adpm_init);
module_exit(adpm_exit);
MODULE_LICENSE("GPL");

